const path=require("path");
const Koa=require("koa");
const logger=require("koa-logger");//产生日志记录
const onerror=require("koa-onerror");//错误链接和转换显示功能
const serve=require("koa-static");
// koa-body 自动完成请求报文解析操作的 = 支持所有的请求报文体的参数类型，并会自动识别
//          并将解析后的报文体参数 定义于 ctx.request.body 中
//          并将解析后的报文体文件数据 定义于 ctx.request.files 中
const koaBody=require("koa-body");
const router=require("./router");
const { historyApiFallback } = require('koa2-connect-history-api-fallback');

const app=new Koa();
app.use(logger());//日志：记录开发中所有的操作流程，当开发出现错误时候，可以快速完成错误定位以及触发错误的源头和执行过程
onerror(app);  // 将控制台错误 映射到 浏览器页面中

// vue-router历史模式兼容服务插件必须定义在所有服务器静态资源之前
//      服务器的请求资源不是只有vue项目一个，还包含其它静态资源和数据接口等
//      历史模式的兼容插件必须准确设置 vue 项目的入口html文件，和被操作的项目目录
//      并通过白名单方式完成其它非vue项目的路径放行
app.use( historyApiFallback({
    // index 用于配置 vue 项目的入口html文件
    // index的路径是以服务器路径为参考的 => http://127.0.0.1:3002/wbs22062-web/index.html
    index:"/wbs22062-web/index.html",
    // 访问路径判断重写，定义放行白名单
    rewrites:[
        {
            // 路径判断依据
            // 通过正则拦截符合条件的请求，经过to配置进行地址转换
            from:new RegExp("^(?!(/wbs22062-web/)).*"), 
            // 重写返回路径
            to:function(content){
                // 将访问路径直接向下进行服务器执行
                return content.parsedUrl.path
            }
        }
    ]
}) );



app.use(koaBody({
    multipart:true,//支持文件上传
    formidable:{
        uploadDir:path.join(__dirname,'./public/upload'),//设置上传文件由二进制数据转上传到服务器的存放目录，文件存储时会完成重新命名操作
        keepExtensions:true//设置是否保留上传文件的后缀名(默认是false)
    }
}));

/* 
静态资源处理中间件(图片，视频，css，js...),不需要服务器进行处理可以直接进行访问的资源
    koa-static中间件可以在koa请求处理时候，判断浏览器访问的相关资源在对应的静态资源目录中是否存在
    如果存在则直接返回该静态资源的相关数据，且中间件不再调用next函数
    如果不存在则直接调用next函数函数访问下一个中间件
koa-static中间件一般被定义在koa请求响应处理中间件的第一行
koa-static中间件在定义时,需要指定一个项目目录作为静态资源的存放目录
koa-static指定的静态资源存放目录，从项目结构上来说，可以认为是服务器的根目录
 */
// app.use(serve("./public"));
let staticPath=path.join(__dirname,'./public');
app.use(serve(staticPath));

// app.use(async function(ctx,next){
//     ctx.set("Access-Control-Allow-Origin","*");//允许指定域名的跨源请求
//     // HTTP 复杂请求
//     // 允许的跨域请求方法的类型
//     ctx.set("Access-Control-Allow-Methods","GET,POST,OPTIONS,PUT,DELETE,PATCH");
//     ctx.set("Access-Control-Allow-Headers","Content-Type,test,Authorization");
//     // 统一的测试请求结果处理
//     if(ctx.method=="OPTIONS"){
//         ctx.body = "";
//     }else{
//         await next();
//     }
// })

const token = require("jsonwebtoken");
let tokenConfig = { 
    sign:token.sign,
    secret:"itant secret" 
}

app.use( async function(ctx,next){
    try {
        ctx.token = tokenConfig;
        await next();
    } catch (error) {
        // console.log("===>",error)
        // console.log("===>",error.status)
        if(error.status==401){
            ctx.status = 401;
            ctx.body = {
                state:false,
                msg:"未授权"
            }
        }else{
            // throw 不对错误进行任何处理，直接进行返回
            throw error;
        }
    }
} )

const jwt = require("koa-jwt");
//  jwt({ sign:加密方法,secret:加密秘钥 })  // 解码+判断授权
//      .unless({ path:正则 }) // 定义不需要判断的路由地址
// app.use( jwt({ sign:加密方法,secret:加密秘钥 }).unless({ path:正则 }) )
app.use( jwt(tokenConfig).unless( { path:[/^\/api\//] } ) )

//router是路由定义对象，用于提供定义时地址和回调函数之间的对应关系
// router完成关系定义后，由router.routes()方法执行完成路由表的生成
// 路由表->一段js的路由和方法对应的判断逻辑
app.use(router.api.routes());
app.use(router.user.routes());


app.listen(3002);